package com.hyt.it.ogt.kq.common.gov.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.IOUtils;
import org.dom4j.DocumentException;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.google.common.base.Charsets;
import com.hyt.it.ogt.kq.common.config.exception.KqException;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import sun.misc.BASE64Decoder;

/**
 * <p>
 *
 * </p>
 *
 * @author Chengxh
 * @since 2021-08-14
 */
@Slf4j
public class FileUtil {

    public static Float getSizeInKb(MultipartFile file) {
        long fileSize = file.getSize();
        return FileUtil.longSizeToFloat(fileSize);
    }

    public static Float longSizeToFloat(long longSize) {
        Float floatSize = Float.parseFloat(String.valueOf(longSize)) / 1024;
        BigDecimal b = BigDecimal.valueOf(floatSize);
        floatSize = b.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
        return floatSize;
    }

    /**
     * FileItem类对象创建
     *
     * @param inputStream inputStream
     * @param fileName    fileName
     * @return FileItem
     */
    public static FileItem createFileItem(InputStream inputStream, String fileName) {
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        String textFieldName = "file";
        FileItem item = factory.createItem(textFieldName, MediaType.MULTIPART_FORM_DATA_VALUE, true, fileName);
        int bytesRead = 0;
        int size = 8192;
        byte[] buffer = new byte[size];
        OutputStream os = null;
        //使用输出流输出输入流的字节
        try {
            os = item.getOutputStream();
            while ((bytesRead = inputStream.read(buffer, 0, size)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            inputStream.close();
        } catch (IOException e) {
            log.error("Stream copy exception", e);
            throw new IllegalArgumentException("文件转换失败");
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    log.error("Stream close exception", e);
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("Stream close exception", e);
                }
            }
        }
        return item;
    }

    public static MultipartFile inputStreamToMultipartFile(String fileName, InputStream inputStream) {
        DiskFileItem fileItem = (DiskFileItem) new DiskFileItemFactory().createItem("file",
                MediaType.MULTIPART_FORM_DATA_VALUE, true, fileName);
        OutputStream os = null;
        try {
            os = fileItem.getOutputStream();
            IOUtils.copy(inputStream, os);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid file: " + e, e);
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    log.error("Stream close exception", e);
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("Stream close exception", e);
                }
            }
        }
        return new CommonsMultipartFile(fileItem);
    }

    /**
     * 获取文件内容
     *
     * @param inputStream
     * @return 文件内容
     * @throws IOException
     */
    public static String getFileContent(InputStream inputStream) throws IOException {
        final int bufferSize = 1024;
        final char[] buffer = new char[bufferSize];
        final StringBuilder out = new StringBuilder();
        Reader in = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
        for (; ; ) {
            int rsz = in.read(buffer, 0, buffer.length);
            if (rsz < 0) {
                break;
            }
            out.append(buffer, 0, rsz);
        }
        String content = out.toString();
        inputStream.close();
        in.close();
        return content;
    }

    /**
     * 删除文件夹
     *
     * @param dir
     * @return
     */
    public static boolean deleteFileOrDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i = 0; i < children.length; i++) {
                boolean success = deleteFileOrDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        //删除空文件夹
        return dir.delete();
    }

    /**
     * 删除文件-创建文件夹
     *
     * @param folder
     * @return
     */
    public static void initFolder(String folder) {
        deleteFile(folder);
        new File(folder).mkdirs();
    }

    /**
     * 删除文件
     *
     * @param filePath
     */
    public static void deleteFile(String filePath) {
        File file = new File(filePath);
        if (file.isDirectory()) {
            Arrays.stream(file.listFiles()).forEach((file1 -> {
                deleteFile(file1.getAbsolutePath());
            }));
        }
        boolean delete = file.delete();
        log.info("删除结果：{} {}",filePath, delete);
    }

    /**
     * 获取zip加密参数
     *
     * @return
     */
    public static ZipParameters getZipParameters() {
        ZipParameters zipParameters = new ZipParameters();
        zipParameters.setEncryptFiles(true);
        zipParameters.setEncryptionMethod(EncryptionMethod.AES);
        return zipParameters;
    }

    /**
     * 解密,使用base64加密过的md5码
     * @param base64
     * @return
     * @throws IOException
     */
    public static String decode(String base64) throws IOException {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] bytes = base64Decoder.decodeBuffer(base64);
        return new String(bytes, Charsets.UTF_8);
    }

    public static String getFileMd5(File file) {
        InputStream in = null;
        try {
            in = new FileInputStream(file);
            String md5 = DigestUtils.md5Hex(in);
            return md5.toUpperCase();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public static String getFileMd5(MultipartFile file) throws Exception {
        try (InputStream in = file.getInputStream()) {
            return DigestUtils.md5Hex(in);
        }
    }

    public static void writeFile(InputStream inputStream, String target) throws IOException {
        writeFile(inputStream, new File(target));
    }

    public static void writeFile(InputStream inputStream, File target) throws IOException {
        if (!target.getParentFile().exists()) {
            target.getParentFile().mkdirs();
        }
        try (BufferedInputStream in = new BufferedInputStream(inputStream); BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(target.toPath()))) {
            byte[] buff = new byte[1024 * 1024];
            int bytesRead = 0;
            while (-1 != (bytesRead = in.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
            bos.flush();
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    /**
     * 获取网络图片的文件流
     * @param fileName
     * @return
     */
    public static InputStream getPhotoUrl(String fileName) {

        InputStream is = null;
        try {
            URL url = new URL(fileName);
            URLConnection con = url.openConnection();
            con.setConnectTimeout(5*1000);
            is = con.getInputStream();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return is;
    }

    @SneakyThrows
    public static void compareResponseCode(String fileName, String fileName2) {

        List<String> codeList = new ArrayList<>();
        try (FileReader file = new FileReader(fileName); BufferedReader br = new BufferedReader(file)) {
            String temp;
            while ((temp = br.readLine()) != null) {
                if (temp.contains(":") && temp.contains("'")) {
                    temp = temp.replaceAll("\\*","")
                            .replaceAll(" ","");
                    System.out.println(temp);
                    temp = temp.split(":")[0];
                    codeList.add(temp);
                }
            }
        }

        List<String> codeList2 = new ArrayList<>();
        try (FileReader file2 = new FileReader(fileName2);BufferedReader br2 = new BufferedReader(file2)) {
            String temp2;
            while ((temp2 = br2.readLine()) != null) {

                if (temp2.contains(":") && temp2.contains("'")) {
                    temp2 = temp2.replaceAll("\\*","")
                            .replaceAll(" ","").split(":")[0];
                    codeList2.add(temp2);
                }
            }
        }

        System.out.println("fileName中多余的code：");
        codeList.stream().forEach(code1 -> {
            if (!codeList2.contains(code1)) {
                //System.out.println(code1);
            }
        });

        System.out.println("fileName2中多余的code：");
        codeList2.stream().forEach(code2 -> {
            if (!codeList.contains(code2)) {
                //System.out.println(code2);
            }
        });

    }

    /**
     * byte数组转File对象
     * @param bytes byte数组
     * @param prefix 文件名前缀
     * @param suffix 文件名后缀
     * @return 文件对象
     */
    public static File bytesToFile(byte[] bytes, String prefix, String suffix) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file;
        try {
            file = File.createTempFile(prefix, suffix);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bytes);
            return file;
        } catch (Exception e) {
            log.error("byte数组转File失败", e);
            throw new KqException();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    log.error("byte数组转File对象BufferedOutputStream关闭失败", e);
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    log.error("byte数组转File对象FileOutputStream关闭失败", e);
                }
            }
        }
    }

    /**
     * byte数组转File对象，写入本地
     * @param bytes byte数组
     * @param target 写入文件的路径
     */
    public static void bytesToFile(byte[] bytes, String target) {
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file;
        try {
            file = new File(target);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bytes);
        } catch (Exception e) {
            log.error("byte数组转File对象，写入本地失败");
            throw new KqException();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    log.error("byte数组转File对象，写入本地BufferedOutputStream关闭失败", e);
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    log.error("byte数组转File对象，写入本地FileOutputStream关闭失败", e);
                }
            }
        }
    }

    public static void main(String[] args) throws IOException, DocumentException {
/*
        ZipFile zipFile = new ZipFile(new File("C:\\Users\\hyt820pc\\Desktop\\证券业从业人员资格考试考试协议.zip"));
        zipFile.setCharset(Charset.forName("GBK"));
        List<FileHeader> fileHeaders = zipFile.getFileHeaders();
        fileHeaders.stream().forEach(item -> {
            System.out.println(item.getFileName());
        });*/

        String fileName = "C:\\Users\\cbadpig\\Desktop\\新建文件夹\\fileName.txt";
        String fileName2 = "C:\\Users\\cbadpig\\Desktop\\新建文件夹\\fileName2.txt";

        compareResponseCode(fileName,fileName2);
    }

}
